'''The latex_converter module provides a base class from which simple LaTeX
converters may be derived. Subclasses may provide basic
functionality by simply implementing the abstract methods defined in in
LatexConverter, but may also add additional functionality using the
L{extend_vocabulary()<LatexConverter.extend_vocabulary>} method.

LatexConverter is I{not} intended to convert entire TeX or LaTeX
documents. It does not support command definitions, environments, and
many other constructs found in LaTeX documents. It should, however, be
adequate for most small TeX and LaTeX fragments of the type found in
BibTeX bibliographies.

@copyright: (c) 2010, Benjamin Kalish

@license:
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.
'''

import types
import warnings

from simpleparse.common import chartypes
from simpleparse.dispatchprocessor import DispatchProcessor
from simpleparse.dispatchprocessor import dispatchList
from simpleparse.dispatchprocessor import getString
from simpleparse.dispatchprocessor import dispatch
from simpleparse.dispatchprocessor import multiMap
from simpleparse.dispatchprocessor import singleMap
from simpleparse.parser import Parser

from bkn.bibtex.error import BKNBibtexWarning
from bkn.bibtex.error import BKNBibtexError
from bkn.bibtex.utilities import ensure_objects_are_unicode

_BASE_GRAMMAR = r'''
# SUBSTITUTION LIST
# This is where the substitutions which do not control sequences are
# specified. Note that all such substitutions are hungry--the
# substitution will be performed regardless of word boundaries.
>substitution<              := paragraph_break /
                               nonbreaking_space /
                               double_left_quote /
                               double_right_quote /
                               inverted_exclamation_mark /
                               inverted_question_mark /
                               em_dash /
                               en_dash /
                               space


# SUBSTITUTION DEFINITIONS
paragraph_break             := '\n\n'
nonbreaking_space           := '~'
double_left_quote           := '``'
double_right_quote          := "''"
inverted_exclamation_mark   := '!`'
inverted_question_mark      := '?`'
em_dash                     := '---'
en_dash                     := '--'
space                       := whitespace

# FOUNDATIONS
unsupported_control_word    := escape, letters, no_arg
unsupported_control_symbol  := escape, -letter
top                         := latex, EOF!
>latex<                     := (control_sequence_plus / group / math_expression / substitution / superscript / subscript / plain_text)*
symbol_arg                  := group / control_sequence_plus / (ignorespace?, character)
word_arg                    := group / control_sequence_plus / (ignorespace, character)
no_arg                      := ignorespace / ?-letter
<ignorespace>               := whitespace
>group<                     := group_start, latex, group_end
plain_text                  := -(escape / group_start / group_end / display_math / inline_math / substitution / superscript / subscript)+
<escape>                    := '\\'
<group_start>               := '{'
<group_end>                 := '}'
>math_expression<           := (display_math, math_content, display_math) / (inline_math, math_content, inline_math)
>math_content<              := (control_sequence_plus / group / substitution / superscript / subscript / plain_text)*
superscript                 := '^', symbol_arg
subscript                   := '_', symbol_arg
display_math                := '$$'
inline_math                 := '$'
character                   := -EOF

# CONTROL WORD DEFINITIONS ADDED PROGROMATICALLY
'''

# TO DO: implement support for sub and super scripts

class LatexConverter:
    '''An abstract class from which latex converters may be derived.
    @todo: improve documentation
    '''
    
    def __init__(self):
        '''Initializes this LatexConverter. Subclasses must be sure to
        call this if they override this method.'''

        self._control_sequence_definitions = []
        self._control_sequence_callbacks = {} # maps callbacks to num_of_args
        self.math_mode = False
        '''Methods make check this attribute durring processing to determine
        if math mode is in effect.'''
        
        self.parser_changed = True
        self.processor = _LatexConverterDispatchProcessor(self)
        self.extend_vocabulary('acute', '\\\'', 1)
        self.extend_vocabulary('aleph', 'aleph', 0)
        self.extend_vocabulary('ampersand', '&', 0)
        self.extend_vocabulary('asterisk', 'ast', 0)
        self.extend_vocabulary('boldface_start', 'bf', 0)        
        self.extend_vocabulary('breve', 'u', 1)
        self.extend_vocabulary('capital_l_with_stroke', 'L', 0)
        self.extend_vocabulary('capital_thorn', 'TH', 0)
        self.extend_vocabulary('captial_o_slash', 'O', 0)
        self.extend_vocabulary('caron', 'v', 1)
        self.extend_vocabulary('cedilla', 'c', 1)
        self.extend_vocabulary('circumflex', '^', 1)
        self.extend_vocabulary('colon', 'colon', 0)
        self.extend_vocabulary('cyrillic_hard_sign', 'cdprime', 0)
        self.extend_vocabulary('cyrillic_soft_sign', 'cprime', 0)
        self.extend_vocabulary('dollar_sign', '$', 0)
        self.extend_vocabulary('dot_above', '.', 1)
        self.extend_vocabulary('dot_below', 'd', 1)
        self.extend_vocabulary('dotless_i', 'i', 0)
        self.extend_vocabulary('dotless_j', 'j', 0)
        self.extend_vocabulary('double_acute', 'H', 1)
        self.extend_vocabulary('element_of', 'in', 0)        
        self.extend_vocabulary('emphasize', 'emph', 1)        
        self.extend_vocabulary('emphasize_start', 'em', 0)        
        self.extend_vocabulary('eszett', 'ss', 0)
        self.extend_vocabulary('eth', 'DH', 0)
        self.extend_vocabulary('explicit_space', ' ', 0)
        self.extend_vocabulary('grave', '`', 1)
        self.extend_vocabulary('hash_sign', '#', 0)
        self.extend_vocabulary('low_line', 'b', 1)
        self.extend_vocabulary('macron', '=', 1)
        self.extend_vocabulary('newblock', 'newblock', 0)
        self.extend_vocabulary('partial', 'partial', 0)
        self.extend_vocabulary('percent_sign', '%', 0)
        self.extend_vocabulary('plus_or_minus', 'pm', 0)
        self.extend_vocabulary('ring_above', 'r', 1)
        self.extend_vocabulary('small_l_with_stroke', 'l', 0)
        self.extend_vocabulary('small_o_slash', 'o', 0)
        self.extend_vocabulary('small_thorn', 'th', 0)
        self.extend_vocabulary('square_root', 'sqrt', 1)
        self.extend_vocabulary('subscript2', 'sb', 1)
        self.extend_vocabulary('sterling', 'sterling', 0)
        self.extend_vocabulary('tilde', '~', 1)
        self.extend_vocabulary('umlaut', '"', 1)
        self.extend_vocabulary('vertical_bar', 'ver', 0)
        self.extend_vocabulary('small_alpha', 'alpha', 0)
        self.extend_vocabulary('small_beta', 'beta', 0)
        self.extend_vocabulary('small_gamma', 'gamma', 0)
        self.extend_vocabulary('small_delta', 'delta', 0)
        self.extend_vocabulary('small_epsilon', 'epsilon', 0)
        self.extend_vocabulary('small_zeta', 'zeta', 0)
        self.extend_vocabulary('small_eta', 'eta', 0)
        self.extend_vocabulary('small_theta', 'theta', 0)
        self.extend_vocabulary('small_iota', 'iota', 0)
        self.extend_vocabulary('small_kappa', 'kappa', 0)
        self.extend_vocabulary('small_lambda', 'lambda', 0)
        self.extend_vocabulary('small_mu', 'mu', 0)
        self.extend_vocabulary('small_nu', 'nu', 0)
        self.extend_vocabulary('small_xi', 'xi', 0)
        self.extend_vocabulary('small_omicron', 'omicron', 0)
        self.extend_vocabulary('small_pi', 'pi', 0)
        self.extend_vocabulary('small_rho', 'rho', 0)
        self.extend_vocabulary('small_sigma', 'sigma', 0)
        self.extend_vocabulary('small_tau', 'tau', 0)
        self.extend_vocabulary('small_upsilon', 'upsilon', 0)
        self.extend_vocabulary('small_phi', 'phi', 0)
        self.extend_vocabulary('small_chi', 'chi', 0)
        self.extend_vocabulary('small_psi', 'psi', 0)
        self.extend_vocabulary('small_omega', 'omega', 0)
        self.extend_vocabulary('capital_alpha', 'Alpha', 0)
        self.extend_vocabulary('capital_beta', 'Beta', 0)
        self.extend_vocabulary('capital_gamma', 'Gamma', 0)
        self.extend_vocabulary('capital_delta', 'Delta', 0)
        self.extend_vocabulary('capital_epsilon', 'Epsilon', 0)
        self.extend_vocabulary('capital_zeta', 'Zeta', 0)
        self.extend_vocabulary('capital_eta', 'Eta', 0)
        self.extend_vocabulary('capital_theta', 'Theta', 0)
        self.extend_vocabulary('capital_iota', 'Iota', 0)
        self.extend_vocabulary('capital_kappa', 'Kappa', 0)
        self.extend_vocabulary('capital_lambda', 'Lambda', 0)
        self.extend_vocabulary('capital_mu', 'Mu', 0)
        self.extend_vocabulary('capital_nu', 'Nu', 0)
        self.extend_vocabulary('capital_xi', 'Xi', 0)
        self.extend_vocabulary('capital_omicron', 'Omicron', 0)
        self.extend_vocabulary('capital_pi', 'Pi', 0)
        self.extend_vocabulary('capital_rho', 'Rho', 0)
        self.extend_vocabulary('capital_sigma', 'Sigma', 0)
        self.extend_vocabulary('capital_tau', 'Tau', 0)
        self.extend_vocabulary('capital_upsilon', 'Upsilon', 0)
        self.extend_vocabulary('capital_phi', 'Phi', 0)
        self.extend_vocabulary('capital_chi', 'Chi', 0)
        self.extend_vocabulary('capital_psi', 'Psi', 0)
        self.extend_vocabulary('capital_omega', 'Omega', 0)    

    def rebuild_parser(self):
        '''Rebuilds the parser to incorporate any changes to the grammar
        as a result of calls to extend_vocabulary().
        
        Subclasses shouldn't need to override this method.'''
        declaration = '\n'.join([
            _BASE_GRAMMAR,
            '\n'.join(self._control_sequence_definitions),
            '>control_sequence_plus< := ' + '/ \n'.join(self._control_sequence_callbacks.keys()) + '/',
            'unsupported_control_word /',
            'unsupported_control_symbol'
            ])
        self._parser = Parser(declaration, 'top')
        self._parser_changed = False
    
    def extend_vocabulary(self, callback_name, control_sequence, num_of_args):
       '''Adds an additional control sequence to this converter's vocabulary.
       
       Subclasses shouldn't need to override this method.
       
       Note that callback_name must be unique.
       
       @param callback_name:
           the name of a method defined for this class. This method will
           be called to handle the supplied control sequence
       @type callback_name: C{str}
       @param control_sequence:
           the TeX or LaTeX control sequence, minus the initial escape
           character.
       @type control_sequence: C{str}
       @param num_of_args:
           the number of arguments expected by the control sequence.
       @type num_of_args: C{int}
       @note:
            only standard control sequences taking a fixed number of
            required arguments are supported at this time. Optional
            arguments, variable arguments, and arguments with
            non-standard delimiters are not supported.
       @rtype: C{None}
       @todo: raise appropriate error if callback name has already been used
       '''
       
       if self._control_sequence_callbacks.has_key(callback_name):
           # TO DO: raise appropriate error
           pass
       
       if control_sequence.isalpha():
           if num_of_args == 0:
               self._control_sequence_definitions.append(
                   callback_name + " := escape, '" + control_sequence + 
                   "', no_arg")
           else:
               self._control_sequence_definitions.append(
                   callback_name + " := escape, '" + control_sequence + "'" +
                   (", " + 'word_arg') * num_of_args)
       else:
           self._control_sequence_definitions.append(
               callback_name + " := escape, '" + control_sequence + "'" +
               (", " + 'symbol_arg') * num_of_args)
                      
       self._control_sequence_callbacks[callback_name] = num_of_args
       self._parser_changed = True

    def convert(self, latex):
        '''Converts the supplied latex.
        
        Subclasses shouldn't need to override this method.
        
        @param latex: the latex or tex code to be converted
        @type latex: C{str} or C{unicode}
        @return: the result of the conversion
        @rtype: C{str} or C{unicode}
        @raise BKNBibtexError:
            if the input is a Unicode string containing characters which
            cannot be expressed in ASCII.
        @todo: use properly subclassed exceptions
        '''
        ensure_objects_are_unicode(latex)
        latex = ' '.join(latex.split()) # normalize whitespace
        try:
            latex = latex.encode('utf_8') 
        except UnicodeEncodeError: 
            raise BKNBibtexError('LatexConverter.convert() could not ' +
                 'convert string to utf_8.')
        if self._parser_changed:
            self.rebuild_parser()
        self.math_mode = False # just to be on the safe side
        success, resultTrees, nextCharacter = self._parser.parse(latex, processor=self.processor)
        if not success:
           raise Exception('Parsing failed') # TO DO: handle error better
        return ''.join(resultTrees).decode('utf_8')
    
    #{ Predefined callbacks
    
    def asterisk(self):
        r'''Returns an asterisk when a LatexConverter encounters the \ast
        control sequence.'''
        return '*'
    
    def boldface_start(self):
        '''Subclasses may implement this method to start a section of 
        boldfaced text. The default implementation returns an empty
        string.'''
        return ''        

    def colon(self):
        r'''Returns a colon when a LatexConverter encounters the \colon
        control sequence.'''
        return ':'
        
    def dotless_i(self):
        '''Subclasses may implement this method to return a dotless i.
        The default implementation returns a normal i for simplicity's
        sake.'''
        return 'i'

    def dotless_j(self):
        '''Subclasses may implement this method to return a dotless j.
        The default implementation returns a normal j for simplicity's
        sake.'''
        return 'j'

    def emphasize(self, arg):
        '''Subclasses may implement this method to return an emphasized
        version of the argument. The default implementation returns
        the argument unchanged.'''
        return arg     
        
    def emphasize_start(self):
        '''Subclasses may implement this method to start a section of 
        emphasized text. The default implementation returns an empty
        string.'''
        return ''       

    def explicit_space(self):
        r'''Returns a space when LatexConverter encounters the '\ '
        control sequence, whis is often often used after mid-sentence
        periods.'''
        return ' '

    def hash_sign(self):
        r'''Returns a hash sign when a LatexConverter encounters the \#
        control sequence.'''
        return '#'

    def dollar_sign(self):
        r'''Returns a dollar sign when a LatexConverter encounters the \$
        control sequence.'''
        return '$'
    
    def newblock(self):
        r'''The default behavior when LatexConverter encounters the \newblock
        control sequence is to do nothing.'''
        return '%'

    def percent_sign(self):
        r'''Returns a dollar sign when a LatexConverter encounters the \%
        control sequence.'''
        return '%'
    
    def subscript2(self, arg):
        r'''Handles the \sb control sequence. This is defined to simply
        call the subscript method so that 'a_0' and 'a\sb 0' are equivalent.
        '''
        return self.subscript(arg)

    def vertical_bar(self):
        r'''Returns a vertical bar when a LatexConverter encounters the \ver
        control sequence.'''
        return '|'
        
    
    #{ Abstract Methods
    
    def aleph(self):
        '''Subclasses should implement this method to return the
        Hebrew letter
        U{aleph<http://en.wikipedia.org/wiki/Aleph>}.'''
        raise NotImplementedError
    
    def capital_l_with_stroke(self):
        '''Subclasses should implement this method to return a capital
        U{L with stroke<http://en.wikipedia.org/wiki/L_with_stroke>}.'''
        raise NotImplementedError

    def capital_thorn(self):
        '''Subclasses should implement this method to return a
        U{thorn<http://en.wikipedia.org/wiki/Thorn_(letter)>}.'''
        raise NotImplementedError

    def cyrillic_soft_sign(self):
        '''Subclasses should implement this method to return a cyrillic soft sign.'''
        raise NotImplementedError

    def cyrillic_hard_sign(self):
        '''Subclasses should implement this method to return a cyrillic hard sign.'''
        raise NotImplementedError
    
    def double_left_quote(self):
        '''Subclasses should implement this method to return a double left quote.'''
        raise NotImplementedError
    
    def double_right_quote(self):
        '''Subclasses should implement this method to return a double right quote.'''
        raise NotImplementedError

    def element_of(self):
        '''Subclasses should implement this method to return an element of
        symbol.'''
        raise NotImplementedError

    def em_dash(self):
        '''Subclasses should implement this method to return an em dash.'''
        raise NotImplementedError

    def en_dash(self):
        '''Subclasses should implement this method to return an en dash.'''
        raise NotImplementedError

    def eth(self):
        '''Subclasses should implement this method to return an
        lowercase eth (such as might be used to indicate a spin-weighted
        partial derivative).'''
        raise NotImplementedError
    
    def eszett(self):
        '''Subclasses should implement this method to return an eszett.'''
        raise NotImplementedError
        
    def inverted_question_mark(self):
        '''Subclasses should implement this method to return an inverted question mark.'''
        raise NotImplementedError
   
    def inverted_exclamation_mark(self):
        '''Subclasses should implement this method to return an inverted exclamation point.'''
        raise NotImplementedError
    
    def nonbreaking_space(self):
        '''Subclasses should implement this method to return a nonbreaking space.'''
        raise NotImplementedError
    
    def paragraph_break(self):
        '''Subclasses should implement this method to return a paragraph break.'''
        raise NotImplementedError
  
    def acute(self, arg):
        '''Subclasses should implement this method to handle the \\' control sequence.'''
        raise NotImplementedError
        
    def ampersand(self):
        '''Subclasses should implement this method to handle the \\& control sequence.'''
        raise NotImplementedError

    def breve(self, arg):
        '''Subclasses should implement this method to handle the \\u control sequence.'''
        raise NotImplementedError

    def caron(self, arg):
        '''Subclasses should implement this method to handle the \\v control sequence.'''
        raise NotImplementedError

    def cedilla(self, arg):
        '''Subclasses should implement this method to handle the \\c control sequence.'''
        raise NotImplementedError

    def circumflex(self, arg):
        '''Subclasses should implement this method to handle the \\^ control sequence.'''
        raise NotImplementedError

    def dot_above(self, arg):
        '''Subclasses should implement this method to handle the \\. control sequence.'''
        raise NotImplementedError

    def dot_below(self, arg):
        '''Subclasses should implement this method to handle the \\d control sequence.'''
        raise NotImplementedError

    def double_acute(self, arg):
        '''Subclasses should implement this method to handle the \\H control sequence.'''
        raise NotImplementedError

    def grave(self, arg):
        '''Subclasses should implement this method to handle the \\` control sequence.'''
        raise NotImplementedError

    def low_line(self, arg):
        '''Subclasses should implement this method to handle the \\b control sequence.'''
        raise NotImplementedError

    def macron(self, arg):
        '''Subclasses should implement this method to handle the \\= control sequence.'''
        raise NotImplementedError

    def partial(self):
        '''Subclasses should implement this method to handle the \\partial control sequence.'''
        raise NotImplementedError

    def ring_above(self, arg):
        '''Subclasses should implement this method to handle the \\r control sequence.'''
        raise NotImplementedError
    
    def plus_or_minus(self):
        '''Subclasses should implement this method to return a plus or minus sign.'''
        raise NotImplementedError
    
    def small_l_with_stroke(self):
        '''Subclasses should implement this method to handle the \\l control sequence.'''
        raise NotImplementedError
    
    def small_thorn(self):
        '''Subclasses should implement this method to return a lowercase
        thorn U{thorn<http://en.wikipedia.org/wiki/Thorn_(letter)>}.'''
        raise NotImplementedError
    
    def square_root(self, arg):
        '''Subclasses should implement this method to return a notation for
        the square root of the argument.'''
        raise NotImplementedError

    def sterling(self):
        '''Subclasses should implement this method to return a U{pound
        sign<http://en.wikipedia.org/wiki/Pound_sign>}.'''
        raise NotImplementedError

    def subscript(self, arg):
        '''Subclasses should implement this method to return a subscripted
        version of the argument.
        
        Note that this command is called when an underscore is encountered.
        The control sequence '\sb' calls subscript2.
        '''
        raise NotImplementedError

    def superscript(self, arg):
        '''Subclasses should implement this method to return a superscripted
        version of the argument.'''
        raise NotImplementedError

    def tilde(self, arg):
        '''Subclasses should implement this method to handle the \\~ control sequence.'''
        raise NotImplementedError

    def umlaut(self, arg):
        '''Subclasses should implement this method to handle the \\" control sequence.'''
        raise NotImplementedError

    def small_alpha(self):
        '''Subclasses should implement this method to handle the \\alpha control sequence.'''
        raise NotImplementedError

    def small_beta(self):
        '''Subclasses should implement this method to handle the \\beta control sequence.'''
        raise NotImplementedError

    def small_gamma(self):
        '''Subclasses should implement this method to handle the \\gamma control sequence.'''
        raise NotImplementedError

    def small_delta(self):
        '''Subclasses should implement this method to handle the \\delta control sequence.'''
        raise NotImplementedError

    def small_epsilon(self):
        '''Subclasses should implement this method to handle the \\epsilon control sequence.'''
        raise NotImplementedError

    def small_zeta(self):
        '''Subclasses should implement this method to handle the \\zeta control sequence.'''
        raise NotImplementedError

    def small_eta(self):
        '''Subclasses should implement this method to handle the \\eta control sequence.'''
        raise NotImplementedError

    def small_theta(self):
        '''Subclasses should implement this method to handle the \\theta control sequence.'''
        raise NotImplementedError

    def small_iota(self):
        '''Subclasses should implement this method to handle the \\iota control sequence.'''
        raise NotImplementedError

    def small_kappa(self):
        '''Subclasses should implement this method to handle the \\kappa control sequence.'''
        raise NotImplementedError

    def small_lambda(self):
        '''Subclasses should implement this method to handle the \\lambda control sequence.'''
        raise NotImplementedError

    def small_mu(self):
        '''Subclasses should implement this method to handle the \\mu control sequence.'''
        raise NotImplementedError

    def small_nu(self):
        '''Subclasses should implement this method to handle the \\nu control sequence.'''
        raise NotImplementedError

    def small_xi(self):
        '''Subclasses should implement this method to handle the \\xi control sequence.'''
        raise NotImplementedError

    def small_omicron(self):
        '''Subclasses should implement this method to handle the \\omicron control sequence.'''
        raise NotImplementedError

    def small_pi(self):
        '''Subclasses should implement this method to handle the \\pi control sequence.'''
        raise NotImplementedError

    def small_rho(self):
        '''Subclasses should implement this method to handle the \\rho control sequence.'''
        raise NotImplementedError

    def small_sigma(self):
        '''Subclasses should implement this method to handle the \\sigma control sequence.'''
        raise NotImplementedError

    def small_tau(self):
        '''Subclasses should implement this method to handle the \\tau control sequence.'''
        raise NotImplementedError

    def small_upsilon(self):
        '''Subclasses should implement this method to handle the \\upsilon control sequence.'''
        raise NotImplementedError

    def small_phi(self):
        '''Subclasses should implement this method to handle the \\phi control sequence.'''
        raise NotImplementedError

    def small_chi(self):
        '''Subclasses should implement this method to handle the \\chi control sequence.'''
        raise NotImplementedError

    def small_psi(self):
        '''Subclasses should implement this method to handle the \\psi control sequence.'''
        raise NotImplementedError

    def small_omega(self):
        '''Subclasses should implement this method to handle the \\omega control sequence.'''
        raise NotImplementedError

    def capital_alpha(self):
        '''Subclasses should implement this method to handle the \\Alpha control sequence.'''
        raise NotImplementedError

    def capital_beta(self):
        '''Subclasses should implement this method to handle the \\Beta control sequence.'''
        raise NotImplementedError

    def capital_gamma(self):
        '''Subclasses should implement this method to handle the \\Gamma control sequence.'''
        raise NotImplementedError

    def capital_delta(self):
        '''Subclasses should implement this method to handle the \\Delta control sequence.'''
        raise NotImplementedError

    def capital_epsilon(self):
        '''Subclasses should implement this method to handle the \\Epsilon control sequence.'''
        raise NotImplementedError

    def capital_zeta(self):
        '''Subclasses should implement this method to handle the \\Zeta control sequence.'''
        raise NotImplementedError

    def capital_eta(self):
        '''Subclasses should implement this method to handle the \\Eta control sequence.'''
        raise NotImplementedError

    def capital_theta(self):
        '''Subclasses should implement this method to handle the \\Theta control sequence.'''
        raise NotImplementedError

    def capital_iota(self):
        '''Subclasses should implement this method to handle the \\Iota control sequence.'''
        raise NotImplementedError

    def capital_kappa(self):
        '''Subclasses should implement this method to handle the \\Kappa control sequence.'''
        raise NotImplementedError

    def capital_lambda(self):
        '''Subclasses should implement this method to handle the \\Lambda control sequence.'''
        raise NotImplementedError

    def capital_mu(self):
        '''Subclasses should implement this method to handle the \\Mu control sequence.'''
        raise NotImplementedError

    def capital_nu(self):
        '''Subclasses should implement this method to handle the \\Nu control sequence.'''
        raise NotImplementedError

    def capital_xi(self):
        '''Subclasses should implement this method to handle the \\Xi control sequence.'''
        raise NotImplementedError

    def capital_omicron(self):
        '''Subclasses should implement this method to handle the \\Omicron control sequence.'''
        raise NotImplementedError

    def capital_pi(self):
        '''Subclasses should implement this method to handle the \\Pi control sequence.'''
        raise NotImplementedError

    def capital_rho(self):
        '''Subclasses should implement this method to handle the \\Rho control sequence.'''
        raise NotImplementedError

    def capital_sigma(self):
        '''Subclasses should implement this method to handle the \\Sigma control sequence.'''
        raise NotImplementedError

    def capital_tau(self):
        '''Subclasses should implement this method to handle the \\Tau control sequence.'''
        raise NotImplementedError

    def capital_upsilon(self):
        '''Subclasses should implement this method to handle the \\Upsilon control sequence.'''
        raise NotImplementedError

    def capital_phi(self):
        '''Subclasses should implement this method to handle the \\Phi control sequence.'''
        raise NotImplementedError

    def capital_chi(self):
        '''Subclasses should implement this method to handle the \\Chi control sequence.'''
        raise NotImplementedError

    def capital_psi(self):
        '''Subclasses should implement this method to handle the \\Psi control sequence.'''
        raise NotImplementedError

    def capital_omega(self):
        '''Subclasses should implement this method to handle the \\Omega control sequence.'''
        raise NotImplementedError

    def small_o_slash(self):
        '''Subclasses should implement this method to handle the \\o control sequence.'''
        raise NotImplementedError
        
    def captial_o_slash(self):
        '''Subclasses should implement this method to handle the \\O control sequence.'''
        raise NotImplementedError
    
    #} End of abstract methods
    

class _LatexConverterDispatchProcessor(DispatchProcessor):
    '''A simpleparse.dispatchprocessor.DispatchProcessor used internally
    by the latex_converter module.'''
    
    def __init__(self, converter):
        '''Creates a new _LatexConverterDispatchProcessor using the
        supplied LatexConverter.'''
        self.converter = converter

    def __getattr__(self, name):
        '''Calls the converter for missing attributes'''
        if name in self.converter._control_sequence_callbacks.keys():
            def missing_method((tag,start,stop,subtags), buffer):
                map = multiMap(subtags, source=self, buffer=buffer)
                args = map.get('word_arg', []) + map.get('symbol_arg', [])
                return getattr(self.converter, name)(*args)
            return missing_method
        elif name in ['double_left_quote',
                      'double_right_quote',
                      'em_dash',
                      'en_dash',
                      'inverted_question_mark',
                      'inverted_exclamation_mark',
                      'nonbreaking_space',
                      'paragraph_break']:
            def missing_method((tag,start,stop,subtags), buffer):
                return getattr(self.converter, name)()
            return missing_method
        else:
            raise AttributeError, name
 
    def space( self, (tag,start,stop,subtags), buffer ):
        '''Returns a space.'''
        if self.converter.math_mode:
            return ''
        else:
            return ' '
        
    def plain_text( self, (tag,start,stop,subtags), buffer ):
        '''Returns plain text as found in original buffer.'''
        return getString( (tag,start,stop,subtags), buffer)

    def character( self, (tag,start,stop,subtags), buffer ):
        '''Returns a charcter as found in original buffer.'''
        return getString( (tag,start,stop,subtags), buffer)
    
    def word_arg( self, (tag,start,stop,subtags), buffer ):
        return ''.join(dispatchList(self, subtags, buffer))

    def symbol_arg( self, (tag,start,stop,subtags), buffer ):
        return ''.join(dispatchList(self, subtags, buffer))
    
    def no_arg( self, (tag,start,stop,subtags), buffer ):
        return ''
    
    def EOF( self, (tag,start,stop,subtags), buffer ):
        return ''

    def unsupported_control_word( self, (tag,start,stop,subtags), buffer ):
        control_word = getString( (tag,start,stop,subtags), buffer).strip()
        message = 'Unsupported control word "{0}".'.format(control_word)
        warnings.warn(message, BKNBibtexWarning)
        return control_word

    def unsupported_control_symbol( self, (tag,start,stop,subtags), buffer ):
        control_symbol = getString( (tag,start,stop,subtags), buffer)
        message = 'Unsupported control symbol "{0}".'.format(control_symbol)
        warnings.warn(message, BKNBibtexWarning)
        return control_symbol
    
    def inline_math( self, (tag,start,stop,subtags), buffer ):
        self.converter.math_mode = not self.converter.math_mode
        return ''

    def display_math( self, (tag,start,stop,subtags), buffer ):
        self.converter.math_mode = not self.converter.math_mode
        return ''

    def superscript( self, (tag,start,stop,subtags), buffer ):
        map = multiMap(subtags, source=self, buffer=buffer)
        arg = map.get('symbol_arg', [])[0]
        return self.converter.superscript(arg)

    def subscript( self, (tag,start,stop,subtags), buffer ):
        map = multiMap(subtags, source=self, buffer=buffer)
        arg = map.get('symbol_arg', [])[0]
        return self.converter.subscript(arg)

